Easiest thing
Distribute Objects!

Remote calls
What if there are tens of remotes calls in between classes?
What's a good interface for remote calls?
=>
You need a for-remote-calls interface!
First Law of Distributed Object Design
DO NOT DISTRIBUTE OBJECTS
Instead use
Clustering
Clustering

Therefore, putting several copies of the application on different places
Boundaries: Forced to Separate
Sometimes it's inevitable to separate things:
- Client / Server
- Server-Based Applications such as Database Servers
- Web Server and Application Server
- Vendor Difference
Cline
Good practices
- Remote Objects
- Lazy Loaders
Helpers
<?php echo input_tag
('nickname') ?>
=> <input type="text" name="nickname" id="nickname" value="" />
uses
function input_tag($name, $value = null)
{
return '<input type="text" name="'.$name.'" id="'.$name.'"value="'.$value.'" />';
}
Needed to be declared
// Use a specific helper group in this template
<?php use_helper
('Text') ?>
...
<h1>Description</h1>
<p>
<?php echo auto_link_text
($description) ?></p>
Common Helpers
Helper
: Required for helper inclusion (the use_helper()
function is, in fact, a helper itself)
Tag
: Basic tag helper, used by almost every helper
Url
: Links and URL management helpers
Asset
: Helpers populating the HTML
section, and providing easy links to external assets (images, JavaScript, and style sheet files)
Partial
: Helpers allowing for inclusion of template fragments
Cache
: Manipulation of cached code fragments
Form
: Form input helpers
Frequently Used Helpers
// Helper group
<?php use_helper
('HelperName') ?>
<?php use_helper
('HelperName1', 'HelperName2', 'HelperName3') ?>
// Tag group
<?php echo tag
('input', array('name' => 'foo', 'type' => 'text')) ?>
<?php echo tag
('input', 'name=foo type=text') ?> // Alternative options syntax
=> <input name="foo" type="text" />
<?php echo content_tag
('textarea', 'dummy content', 'name=foo') ?>
=> <textarea name="foo">dummy content</textarea>
// Url group
<?php echo link_to
('click me', 'mymodule/myaction') ?>
=> <a href="/route/to/myaction">click me</a> // Depends on the routing settings
// Asset group
<?php echo image_tag
('myimage', 'alt=foo size=200x100') ?>
=> <img src="/images/myimage.png" alt="foo" width="200" height="100"/>
<?php echo javascript_include_tag
('myscript') ?>
=> <script language="JavaScript" type="text/javascript" src="/js/myscript.js"></script>
<?php echo stylesheet_tag
('style') ?>
=> <link href="/stylesheets/style.css" media="screen" rel="stylesheet"type="text/css" />
Layouts/Templates

Available Objects in Templates
$sf_context
$sf_request
$sf_params
$sf_user
Example:
// Long version
<?php echo $sf_request->getParameter('total') ?>
// Shorter version
<?php echo $sf_params->get('total') ?>
// Equivalent to the following action code
echo $request->getParameter('total')
$sf_user->getAttribute('attribute');
<?php include(sfConfig::get('sf_app_template_dir').'/myFragment.php') ?>
This has many problems:
- Not well integrated with symfony (Cashing, etc.)
Symfony's Solution
- Partials
- Components
- Slots
- Component Slots
Partials

Examples
<?php include_partial('mypartial1') ?>
<?php include_partial('foobar/mypartial2') ?>
<?php include_partial('global/mypartial3') ?>
Passing Parameters
Partials do not have access to Symfony's variables.
<p>Hello, world!</p>
<?php include_partial
('mypartial', array('mytotal' => $total)) ?>
They are like partials, but have their own logic!
Example: News headlines
modules/news/actions/components.class.php
<?php
class newsComponents extends sfComponents
{
public function executeHeadlines()
{
$c = new Criteria();
$c->addDescendingOrderByColumn(NewsPeer::PUBLISHED_AT);
$c->setLimit(5);
$this->news = NewsPeer::doSelect($c);
}
}
modules/news/templates/_headlines.php
<div>
<h1>Latest news</h1>
<ul>
<?php foreach($news as $headline): ?>
<li>
<?php echo $headline->getPublishedAt() ?>
<?php echo link_to
($headline->getTitle(),'news/show?id='.$headline->getId()) ?>
</li>
<?php endforeach ?>
</ul>
</div>
Usage
<?php include_component('news', 'headlines') ?>
<div id="sidebar">
<?php if (has_slot('sidebar')): ?>
<?php include_slot('sidebar') ?>
<?php else: ?>
<!-- default sidebar code -->
<h1>Contextual zone</h1>
<p>This zone contains links and information
relative to the main content of the page.</p>
<?php endif; ?>
</div>
or
<div id="sidebar">
<?php if (!include_slot('sidebar')): ?>
<!-- default sidebar code -->
<h1>Contextual zone</h1>
<p>This zone contains links and information
relative to the main content of the page.</p>
<?php endif; ?>
</div>
<?php slot
('sidebar') ?>
<!-- custom sidebar code for the current template-->
<h1>User details</h1>
<p>name:
<?php echo $user->getName() ?></p>
<p>email:
<?php echo $user->getEmail() ?></p>
<?php end_slot
() ?>
or
<?php slot('title', 'The title value') ?>
set slot in actions
$this->getResponse()->setSlot('mySlot', $myValue);
$this->getResponse()->setSlot('myPartialSlot', $this->getPartial('myPartial'));
Application Level
default:
http_metas:
content-type: text/html
metas:
#title: symfony project
#description: symfony project
#keywords: symfony, project
#language: en
robots: index, follow
stylesheets: [main]
javascripts: []
has_layout: on
layout: layout
Module Level
all:
stylesheets: [my_style]
metas:
title: My website
View Configuration
editSuccess:
metas:
title: Edit your profile
editError:
metas:
title: Error in the profile edition
all:
stylesheets: [my_style]
metas:
title: My website
class mymoduleActions extends sfActions
{
public function executeIndex()
{
$response = $this->getResponse();
// HTTP headers
$response->setContentType('text/xml');
$response->setHttpHeader('Content-Language', 'en');
$response->setStatusCode(403);
$response->addVaryHttpHeader('Accept-Language');
$response->addCacheControlHttpHeader('no-cache');
// Cookies
$response->setCookie($name, $content, $expire, $path, $domain);
// Metas and page headers
$response->addMeta('robots', 'NONE');
$response->addMeta('keywords', 'foo bar');
$response->setTitle('My FooBar Page');
$response->addStyleSheet('custom_style');
$response->addJavaScript('custom_behavior');
}
}
$response->setContentType('text/xml');
echo $response->getContentType();
=> 'text/xml; charset=utf-8'
$response->setStatusCode(404, 'This page does not exist');
File Inclusion
// In the view.yml
indexSuccess:
stylesheets: [mystyle1, mystyle2]
javascripts: [myscript]
// In the action
$this->getResponse()->addStylesheet('mystyle1');
$this->getResponse()->addStylesheet('mystyle2');
$this->getResponse()->addJavascript('myscript');
// In the Template
<?php use_stylesheet('mystyle1') ?>
<?php use_stylesheet('mystyle2') ?>
<?php use_javascript('myscript') ?>
Changing Layout
// In view.yml
indexSuccess:
layout: my_layout
// In the action
$this->setLayout('my_layout');
// In the template
<?php decorate_with('my_layout') ?>
no Layout:
Listing 7-37 - Layout Removal
// In `view.yml`
indexSuccess:
has_layout: false
// In the Action
$this->setLayout(false);
// In the template
<?php decorate_with(false) ?>
...
<div id="sidebar">
<?php include_component_slot('sidebar') ?>
</div>
in frontend/config/view.yml
default:
components:
sidebar: [bar, default]